package cn.edu.stu.syllabus.library.list;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import cn.edu.stu.syllabus.datas.RequestState;
import cn.edu.stu.syllabus.oa.list.OaPresenter;
import cn.edu.stu.syllabus.repository.library.LibraryRepository;
import cn.edu.stu.syllabus.repository.library.LibrarySearchInfo;
import cn.edu.stu.syllabus.repository.library.local.BookEntry;
import cn.edu.stu.syllabus.repository.library.local.BooksResultEntry;
import cn.edu.stu.syllabus.utils.ExtraNameJoiner;
import cn.edu.stu.syllabus.utils.ListUtils;
import cn.edu.stu.syllabus.utils.RxSchedulerUtils;
import rx.Subscriber;
import rx.Subscription;
import rx.subscriptions.CompositeSubscription;

import static cn.edu.stu.syllabus.utils.NullPointerUtils.checkNotNull;

/**
 * Created by daidaijie on 2017/3/27.
 */

public class QueryBooksListPresenter implements QueryBooksListContract.Presenter {

    private final QueryBooksListContract.View mView;

    private final LibraryRepository mLibraryRepository;

    private final LibrarySearchInfo mLibrarySearchInfo;

    private CompositeSubscription mCompositeSubscription;

    private static final int BOOKS_PAGE_NUM = 20;

    private static final String EXTRA_BOOK_ENTRY = ExtraNameJoiner.join(
            QueryBooksListPresenter.class, "mBookEntries"
    );

    private static final String EXTRA_PAGE = ExtraNameJoiner.join(
            QueryBooksListPresenter.class, "mPage"
    );

    private static final String EXTRA_LASE_URL = ExtraNameJoiner.join(
            QueryBooksListPresenter.class, "mLastUrl"
    );

    private static final String EXTRA_SEARCH_NUM = ExtraNameJoiner.join(
            QueryBooksListPresenter.class, "mSearchNum"
    );

    private static final String EXTRA_REQUEST_STATE = ExtraNameJoiner.join(
            QueryBooksListPresenter.class, "mRequestState"
    );

    private int mRequestState;

    private int mPage;

    private String mLastUrl;

    private List<BookEntry> mBookEntries;

    private long mSearchNum;

    @Inject
    public QueryBooksListPresenter(QueryBooksListContract.View view,
                                   LibraryRepository libraryRepository,
                                   LibrarySearchInfo librarySearchInfo) {
        mView = checkNotNull(view);
        mLibraryRepository = checkNotNull(libraryRepository);
        mLibrarySearchInfo = checkNotNull(librarySearchInfo);
        mCompositeSubscription = new CompositeSubscription();
    }

    @Inject
    public void setupListener() {
        mView.setPresenter(this);
    }

    @Override
    public void subscribe() {
        if (mBookEntries == null) {
            if (RequestState.REQUEST_ERROR == mRequestState) {
                mView.showDataError();
            } else if (RequestState.REQUEST_EMPTY == mRequestState) {
                mView.showDataEmpty();
            } else {
                mRequestState = RequestState.REQUEST_FIRST;
                loadBookList();
            }
        } else {
            mView.setBookList(mBookEntries);
            mView.showQueryNum(mSearchNum);
            if (RequestState.REQUEST_ERROR == mRequestState) {
                mView.showLoadingFail();
            } else if (RequestState.REQUEST_EMPTY == mRequestState) {
                mView.showLoadingEnd();
            }
        }

    }

    @Override
    public void unsubscribe() {
        mCompositeSubscription.unsubscribe();
    }

    @Override
    public void loadBookList() {
        if (RequestState.isFirst(mRequestState)) {
            mPage = 1;
            mLastUrl = "";
            mSearchNum = 0;
        }

        Subscription subscription = mLibraryRepository.getBooksResult(mLibrarySearchInfo, mPage, BOOKS_PAGE_NUM)
                .compose(RxSchedulerUtils.<BooksResultEntry>io2mainSchedulersTransformer())
                .subscribe(new Subscriber<BooksResultEntry>() {
                    @Override
                    public void onStart() {
                        if (RequestState.isFirst(mRequestState)) {
                            mView.showRefreshing(true);
                            mView.setRecyclerViewEnable(false);
                        }
                    }

                    @Override
                    public void onCompleted() {
                        mView.showRefreshing(false);
                        mView.setRecyclerViewEnable(true);
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (mLibraryRepository.isSourceEmpty(e)) {
                            if (RequestState.isFirst(mRequestState)) {
                                mView.showDataEmpty();
                            } else {
                                mView.showLoadingEnd();
                            }
                            mRequestState = RequestState.REQUEST_EMPTY;
                        } else {
                            if (RequestState.isFirst(mRequestState)) {
                                mView.showDataError();
                            } else {
                                mView.showLoadingFail();
                            }
                            mRequestState = RequestState.REQUEST_ERROR;
                        }
                        mView.showRefreshing(false);
                        mView.setRecyclerViewEnable(true);
                    }

                    @Override
                    public void onNext(BooksResultEntry booksResultEntry) {
                        if (ListUtils.getListSizeSafety(booksResultEntry.bookEntries) > 0) {

                            String currentLastUrl = booksResultEntry.bookEntries
                                    .get(booksResultEntry.bookEntries.size() - 1).getUrl();

                            if (currentLastUrl.equals(mLastUrl)) {
                                if (RequestState.isFirst(mRequestState)) {
                                    mView.showDataEmpty();
                                } else {
                                    mView.showLoadingEnd();
                                }
                                mRequestState = RequestState.REQUEST_EMPTY;
                            } else {
                                if (RequestState.isFirst(mRequestState)) {
                                    mSearchNum = booksResultEntry.searchNum;
                                    mView.showQueryNum(mSearchNum);
                                    mBookEntries = booksResultEntry.bookEntries;
                                    mView.setBookList(booksResultEntry.bookEntries);
                                    mView.moveToTop();
                                } else {
                                    mView.appendBookList(booksResultEntry.bookEntries);
                                }
                                mRequestState = RequestState.REQUEST_SUCCESS;
                                mLastUrl = currentLastUrl;
                                mPage += 1;
                            }

                        } else {
                            if (RequestState.isFirst(mRequestState)) {
                                mView.showDataEmpty();
                            } else {
                                mView.showLoadingEnd();
                            }
                            mRequestState = RequestState.REQUEST_EMPTY;
                        }
                    }
                });
        mCompositeSubscription.add(subscription);
    }

    @Override
    public void resetRefreshing() {
        mRequestState = RequestState.REQUEST_FIRST;
    }

    @Override
    public Map<String, Object> getStoreData() {
        Map<String, Object> storeData = new HashMap<>();
        storeData.put(EXTRA_BOOK_ENTRY, mBookEntries);
        storeData.put(EXTRA_SEARCH_NUM, mSearchNum);
        storeData.put(EXTRA_LASE_URL, mLastUrl);
        storeData.put(EXTRA_PAGE, mPage);
        storeData.put(EXTRA_REQUEST_STATE, mRequestState);
        return storeData;
    }

    @Override
    public void restoreData(Map<String, Object> storeData) {
        mBookEntries = (List<BookEntry>) storeData.get(EXTRA_BOOK_ENTRY);
        mSearchNum = (long) storeData.get(EXTRA_SEARCH_NUM);
        mLastUrl = (String) storeData.get(EXTRA_LASE_URL);
        mPage = (int) storeData.get(EXTRA_PAGE);
        mRequestState = (int) storeData.get(EXTRA_REQUEST_STATE);
    }
}
